package com.wgo.preciseLite.server;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.Transaction;

import test.HibernateUtil;

import com.wgo.precise.common.VO.Persistent;
import com.wgo.precise.common.VO.Project;
import com.wgo.precise.common.VO.RequirementSystem;
import com.wgo.precise.common.service.PreciseService;
import com.wgo.precise.common.service.SaveRequest;
import com.wgo.precise.server.ejb.DomainFactoryEjb;
import com.wgo.preciseLite.server.transform.ExportService;
import com.wgo.preciseLite.server.transform.xml.ExportPreciseLiteXml;

public class PreciseServiceHibernateImpl implements PreciseService 
{
	private final ExportService xmlExport;
	private final String requiremntSystemName = "system";
	
	public PreciseServiceHibernateImpl()
	{
		xmlExport = new ExportPreciseLiteXml();
	}

	public Project getProject(String name) throws RemoteException 
	{
		Session sess = HibernateUtil.getSessionFactory().openSession();		
	  	DomainFactoryEjb domainFactory = new DomainFactoryEjb(sess);            
		Transaction tx = sess.beginTransaction();

		com.wgo.precise.common.domain.Project p = domainFactory.findProjectByKey(name);
		
		tx.commit();
		sess.flush();
		sess.close();
		
		return new Project(p,2);

	}

	public RequirementSystem getRequirementSystem(String name)
			throws RemoteException 
	{
		try {
			System.out.println("Requesting Requirement System");
			Session sess = HibernateUtil.getSessionFactory().openSession();		
			DomainFactoryEjb domainFactory = new DomainFactoryEjb(sess);            
			Transaction tx = sess.beginTransaction();

			com.wgo.precise.common.domain.RequirementSystem r = domainFactory.findRequirementSystemByKey(name);

			RequirementSystem rs = new RequirementSystem(r,7);
			tx.commit();
			sess.flush();
			sess.close();

			return rs;
		} catch (Throwable e) {
			System.err.println("Unable to retrieve root system: " + e.getMessage());
			e.printStackTrace();
			throw new RemoteException(e.getMessage());
		}
	}

//	public HashMap<Long, Long> saveAll(List<SaveRequest<? extends Persistent>> saveRequests) 
//	{
//		Session sess = HibernateUtil.getSessionFactory().openSession();		
//	  	DomainFactoryEjb domainFactory = new DomainFactoryEjb(sess);            
//		Transaction tx = sess.beginTransaction();
//		HashMap<Object,Long>newObjects=new HashMap<Object,Long>();
//		
//		HashMap<Long,Long> idMap = new HashMap<Long, Long>();
//		
//		for( SaveRequest sr : saveRequests)
//		{
//			System.out.println(" Request type  : " + sr.getSessionType() + " " 
//					         + sr.getClassType() + " " + sr.getObj().toString());
//			
//			if( sr.getSessionType() == com.wgo.precise.client.session.Session.Type.MODIFIED)
//			{
//				sr.copy(domainFactory.find(sr.getDomainClassType(), sr.getId()));
//				//sess.saveOrUpdate(o);
//			    System.out.println("Modifying : " + sr.getDomainClassType());
//			}
//			else if( sr.getSessionType() == com.wgo.precise.client.Session.Type.NEW)
//			{
//				Object c = domainFactory.create(sr.getDomainClassType());
//				
//				sr.copy(c);
//				newObjects.put(c,sr.getId());
//
//				Object o = domainFactory.find(sr.getParentDomainClassType(),sr.getParentId());
//				sr.addProperty(o);
//				sess.saveOrUpdate(o);
//				System.out.println("Creating new : " + sr.getDomainClassType());
//				 
//			}
//			else if( sr.getSessionType() == com.wgo.precise.client.Session.Type.ADDED)
//			{
//				if(newObjects.containsValue(sr.getId())){
//					Object o = findNewObject(sr.getId(),newObjects);
//					sr.copy(o);
//				}
//				else
//					sr.copy(domainFactory.find(sr.getDomainClassType(),sr.getId()));
//				
//				Object o = domainFactory.find(sr.getParentDomainClassType(), sr.getParentId());
//				sr.addProperty(o);
//				sess.saveOrUpdate(o);
//				System.out.println("Adding relation : " + sr.getDomainClassType());
//			}
//			
//			else if( sr.getSessionType() == com.wgo.precise.client.Session.Type.DELETED)
//			{
//	
//			     Object o = domainFactory.find(sr.getDomainClassType(),sr.getId());
//			     Object p = domainFactory.find(sr.getParentDomainClassType(),sr.getParentId());
//			     //sr.removeProperty(o,p);
//			     //sess.saveOrUpdate(p);
//			     sess.delete(o);
//				 System.out.println("Deleting object : " + sr.getDomainClassType());
//			}
//		}
//		
//		tx.commit();
//		
//		Iterator<Object> it=newObjects.keySet().iterator();
//		while(it.hasNext())
//		{
//			Object o = it.next();
//			idMap.put(newObjects.get(o), getDBId(o));
//		}
//		
//		sess.flush();
//		sess.close();
//		return idMap;
//	}
	
	public HashMap<Long, Long> saveAll(List<SaveRequest> saveRequests)
			throws RemoteException {
		HashMap<Long,Long> idMap = new HashMap<Long, Long>();
		try {
			Session sess = HibernateUtil.getSessionFactory().openSession();		
			DomainFactoryEjb domainFactory = new DomainFactoryEjb(sess);             
			Transaction tx = sess.beginTransaction();
			HashMap<Object,Long>newObjects=new HashMap<Object,Long>();

			for( SaveRequest sr : saveRequests)
			{
				System.out.println(" Request type  : " + sr.getSessionType() + " " 
						+ sr.getClassType() + " " + sr.getObj().toString());

				if( sr.getSessionType() == com.wgo.precise.client.session.Session.Type.MODIFIED)
				{
					sr.copy((com.wgo.precise.common.domain.Persistent)domainFactory.find(sr.getClassType(), sr.getId()));
					System.out.println("Modifying : " + sr.getClassType());
				}
				else if( sr.getSessionType() == com.wgo.precise.client.session.Session.Type.NEW)
				{
					Object c = domainFactory.create(sr.getClassType());

					sr.copy((com.wgo.precise.common.domain.Persistent) c);
					newObjects.put(c,sr.getId());

					if(newObjects.containsValue(sr.getParentId())){
						Object o = findNewObject(sr.getParentId(),newObjects);
						if(o!=null)
							sr.addProperty((com.wgo.precise.common.domain.Persistent) o);
					}
					else{
						if(sr.getParentClassType()!=null){
							Object o = domainFactory.find(sr.getParentClassType(),sr.getParentId());
							if(o!=null)
								sr.addProperty((com.wgo.precise.common.domain.Persistent) o);
						}
					}

					sess.saveOrUpdate(c);
					System.out.println("Creating new : " + sr.getClassType());

				}
				else if( sr.getSessionType() == com.wgo.precise.client.session.Session.Type.ADDED){

					if(newObjects.containsValue(sr.getId())){
						Object o = findNewObject(sr.getId(),newObjects);
						sr.copy((com.wgo.precise.common.domain.Persistent) o);
					}
					else
						sr.copy((com.wgo.precise.common.domain.Persistent) domainFactory.find(sr.getClassType(),sr.getId()));
					if(newObjects.containsValue(sr.getParentId())){
						Object o = findNewObject(sr.getParentId(),newObjects);
						sr.addProperty((com.wgo.precise.common.domain.Persistent) o);
					}
					else{
						if(sr.getParentClassType()!=null){
							Object o = domainFactory.find(sr.getParentClassType(), sr.getParentId());
							sr.addProperty((com.wgo.precise.common.domain.Persistent) o);
						}
					}
				}
				else if(sr.getSessionType() == com.wgo.precise.client.session.Session.Type.REMOVED){
					if(newObjects.containsValue(sr.getId())){
						Object o = findNewObject(sr.getId(),newObjects);
						sr.copy( (com.wgo.precise.common.domain.Persistent) o);
					}
					else
						sr.copy((com.wgo.precise.common.domain.Persistent) domainFactory.find(sr.getClassType(),sr.getId()));

					if(newObjects.containsValue(sr.getParentId())){
						Object o = findNewObject(sr.getParentId(),newObjects);
						sr.removeProperty((com.wgo.precise.common.domain.Persistent) o);
					}
					else{
						if(sr.getParentClassType()!=null){
							Object o = domainFactory.find(sr.getParentClassType(), sr.getParentId());
							sr.removeProperty((com.wgo.precise.common.domain.Persistent) o);
						}
					}
				}
				else if( sr.getSessionType() == com.wgo.precise.client.session.Session.Type.DELETED)
				{

					Object o = domainFactory.find(sr.getClassType(),sr.getId());
					sess.delete(o);
					System.out.println("Deleting object : " + sr.getClassType());
				}
			}

			tx.commit();

			Iterator<Object> it=newObjects.keySet().iterator();
			while(it.hasNext()){
				Object o = it.next();
				Long oldID = newObjects.get(o);
				idMap.put(oldID, getDBId(o));
			}

			sess.flush();
			sess.close();
		} catch (Throwable e){
			System.err.print(e);
			throw e;
		} finally {
			return idMap;
		}
	}

	
	private Object findNewObject(long id, HashMap<Object, Long> newObjects) 
	{
		Iterator<Object> it = newObjects.keySet().iterator();
		while(it.hasNext())
		{
			Object o = it.next();
			if(newObjects.get(o)==id){
				return o;
			}
		}
		return null;
	}

	private long getDBId(Object o) 
	{
		if(o instanceof com.wgo.precise.common.domain.Persistent)
		{
			com.wgo.precise.common.domain.Persistent p = (com.wgo.precise.common.domain.Persistent) o;
			return p.getDbId();
		}

		return -1;
	}

	/* (non-Javadoc)
	 * @see com.wgo.precise.common.service.PreciseService#exportToXml()
	 */
	@Override
	public byte[] exportToXml() throws RemoteException {
		Session sess = HibernateUtil.getSessionFactory().openSession();		
		try {
			System.out.println("Exporting to XML");
			DomainFactoryEjb domainFactory = new DomainFactoryEjb(sess);            
			Transaction tx = sess.beginTransaction();
			com.wgo.precise.common.domain.RequirementSystem requirementSystem = domainFactory.findRequirementSystemByKey(requiremntSystemName);
			return xmlExport.export(requirementSystem);
		} catch (Throwable e) {
			System.err.println("Unable to export to xml root system: " + e.getMessage());
			e.printStackTrace();
			throw new RemoteException(e.getMessage());
		} finally {
			sess.flush();
			sess.close();
		}
		
	}

	
}
